import * as d3 from "d3";

function StudentDistribution(data, { 
  sortedData = [...data].sort((a, b) => a.latitude - b.latitude),
  marginTop = 40,
  marginRight = 30,
  marginBottom = 40,
  marginLeft = 100,
  width = 800,
  height = 700,
  x = d => +d.count,
  xType = d3.scaleLinear, // type of x-scale
  xDomain = [0, 100], // [xmin, xmax]
  xRange = [marginLeft, width - marginRight], // [left, right]
  y = d => +d.latitude,
  yType = d3.scaleLinear, // type of y-scale
  yDomain = [22.5, 47.5], // [ymin, ymax]
  yRange = [height - marginBottom, marginTop], // [bottom, top]
} = {}) {
  const thresholds = d3.range(22.5, 47.5, 0.5);
  const bins = d3.bin().domain(yDomain).thresholds(thresholds);
  const binnedData = bins(data.map(y)).map((bin) => {
    const count = data.filter(d => 
      y(d) >= bin.x0 && y(d) <= bin.x1
    ).reduce((sum, d) => sum + x(d), 0);
    return {
      minLatitude: bin.x0,
      maxLatitude: bin.x1,
      count: Math.max(count, 0.5)
    };
  });

  const xScale = xType().domain(xDomain).range(xRange);

  const yScale = yType().domain(yDomain).range(yRange);
  
  // 创建 SVG 容器。
  const svg = d3.select("#student-distribution")
      .attr("width", width)
      .attr("height", height)
      .attr("viewBox", [0, 0, width, height])
      .attr("style", "max-width: 100%; height: auto;");

  // 添加x轴标注
  svg.append("g")
    .attr("transform", `translate(${marginLeft},${height - marginBottom})`)
    .call(g => {
      // 创建一个短的轴线
      g.call(d3.axisBottom(xScale)
        .tickValues([])
        .tickSize(0));
      
      // 设置轴线长度和方向
      g.select(".domain")
        .attr("d", "M0,0H-50")
        .attr("marker-end", "url(#arrow)")
        .attr("stroke", "#cccccc")
        .attr("stroke-dasharray", "4,4");
      
      // 添加箭头定义
      svg.append("defs")
        .append("marker")
        .attr("id", "arrow")
        .attr("viewBox", "0 0 10 10")
        .attr("refX", 5)
        .attr("refY", 5)
        .attr("markerWidth", 6)
        .attr("markerHeight", 6)
        .attr("orient", "auto")
        .append("path")
        .attr("d", "M 0 0 L 10 5 L 0 10 z")
        .attr("fill", "#cccccc");
      
      // 添加"学生数量"标签
      g.append("text")
        .attr("x", -25)
        .attr("y", 20)
        .attr("fill",  "#666666")
        .attr("text-anchor", "middle")
        .attr("font-size", "12px")
        .text("学生数量");
    });

  // 添加省份标记点
  svg.selectAll(".province-dot")
    .data(sortedData)
    .join("circle")
    .attr("class", "province-dot")
    .attr("cx", marginLeft)
    .attr("cy", d => yScale(d.latitude))
    .attr("r", 1.5)
    .attr("fill", "rgb(135, 206, 235)");

  // 创建省份标签偏移映射
  const labelOffsets = {
    "河北": -5,
    "山西": 5,
    "江苏": -5,
    "安徽": 5,
    "四川": -5,
    "湖北": 5
  };

  // 添加省份标签
  svg.selectAll(".province-label")
    .data(sortedData)
    .join("text")
    .attr("class", "province-label")
    .attr("x", marginLeft + 5)
    .attr("y", d => yScale(d.latitude) + (labelOffsets[d.province] || 0)) // 添加偏移量
    .attr("dy", "0.35em")
    .attr("font-size", "10px")  
    .text(d => d.province);

  // 创建区域渐变
  const areaGradient = svg.append("defs")
    .append("linearGradient")
    .attr("id", "areaGradient")
    .attr("x1", "0%")
    .attr("x2", "100%");
  
  areaGradient.append("stop")
    .attr("offset", "0%")
    .attr("stop-color", "rgba(135, 206, 235, 0.9)");
  
  areaGradient.append("stop")
    .attr("offset", "100%")
    .attr("stop-color", "rgba(135, 206, 235, 0.2)");

  // 创建曲线生成器
  const area = d3.area()
    .x0(d => xScale(-d.count))
    .x1(marginLeft)
    .y((d, i, data) => {
      // 对于第一个点使用区间下界，最后一个点使用区间上界，其他使用中点
      if (i === 0) return yScale(d.minLatitude);
      if (i === data.length - 1) return yScale(d.maxLatitude);
      return yScale((d.minLatitude + d.maxLatitude) / 2);
    })
    .curve(d3.curveBumpY);

  svg.append("path")
    .datum(binnedData)
    .attr("fill", "url(#areaGradient)")
    .attr("stroke", "rgb(135, 206, 235)")
    .attr("stroke-width", 1)
    .attr("d", area);
  
  // 添加天津标记点
  const tjData = data.find(d => d.province === "天津");
  svg.append("circle")
    .attr("cx", width - 100)
    .attr("cy", yScale(tjData.latitude))
    .attr("r", 3)
    .attr("fill", "rgba(0, 100, 255, 0.5)");
  
  svg.append("text")
    .attr("x", width - 95)
    .attr("y", yScale(tjData.latitude))
    .attr("dy", "0.25em")
    .text("天津")
    .attr("fill", "black");

  // 绘制流线
  svg.selectAll(".link")
    .data(sortedData)
    .join("path")
    .attr("fill", d => {
      const isNorth = d.latitude > 33;
      return isNorth 
        ? "rgba(255, 192, 203, 0.7)"  // 加深粉色
        : "rgba(176, 224, 230, 0.7)"; // 加深蓝色
    })
    .attr("d", d => {
      const sourceX = marginLeft;
      const sourceY = yScale(d.latitude);
      const targetX = width - 100;
      const targetY = yScale(tjData.latitude);
      
      const dx = targetX - sourceX;
          
      // 修改控制点位置以创建向内凹的汇聚效果
      const controlX1 = sourceX + dx * 0.4;
      const controlX2 = sourceX + dx * 0.6;  
          
      // 计算曲线宽度，使用正弦函数使其在中间最宽
      const maxWidth = d.count * 1.5;
      const getWidth = (t) => maxWidth * Math.sin(Math.PI * t);
          
      // 在路径中间点处获得最大宽度
      const midWidth = getWidth(0.5);
          
      return `
        M ${sourceX} ${sourceY}
        C ${controlX1} ${sourceY + getWidth(0.4)}
        ${controlX2} ${targetY + getWidth(0.6)}
        ${targetX} ${targetY}
        L ${targetX} ${targetY}
        C ${controlX2} ${targetY - getWidth(0.6)}
        ${controlX1} ${sourceY - getWidth(0.4)}
        ${sourceX} ${sourceY}
        Z
      `;
    });

  // 计算南北方数据
  const northTotal = sortedData
    .filter(d => d.latitude > 33)
    .reduce((sum, d) => sum + (+d.count), 0);

  const southTotal = sortedData
    .filter(d => d.latitude <= 33)
    .reduce((sum, d) => sum + (+d.count), 0);

  const total = northTotal + southTotal;
  const northPercentage = (northTotal / total * 100).toFixed(1);
  const southPercentage = (southTotal / total * 100).toFixed(1);

  // 添加北方文字标注
  svg.append("text")
    .attr("x", width - 200)
    .attr("y", marginTop + 50)
    .attr("fill", "rgb(255, 192, 203)")
    .attr("font-size", "24px")
    .text(`${northPercentage}%`);

  svg.append("text")
    .attr("x", width - 200)
    .attr("y", marginTop + 70)
    .attr("fill", "rgb(255, 192, 203)")
    .attr("font-size", "14px")
    .attr("font-weight", "bold")
    .text(`来自北方的学生`);

  // 添加南方文字标注
  svg.append("text")
    .attr("x", width - 200)
    .attr("y", height - marginBottom - 70)
    .attr("fill", "rgb(176, 224, 230)")
    .attr("font-size", "24px")
    .text(`${southPercentage}%`);

  svg.append("text")
    .attr("x", width - 200)
    .attr("y", height - marginBottom - 50)
    .attr("fill", "rgb(176, 224, 230)")
    .attr("font-size", "14px")
    .attr("font-weight", "bold")
    .text(`来自南方的学生`);

  // 添加标题
  svg.append("text")
    .attr("x", width / 2)
    .attr("y", marginTop / 2)
    .attr("text-anchor", "middle")
    .attr("font-size", "18px") 
    .attr("fill", "black")
    .text("数据可视化课程生源分布");

  return svg.node();
}

export default StudentDistribution;